<template>
	<view class="container">
		<!-- 控制按钮 -->
		<view class="control-section">
			<button @tap="startScan">🔍 开始扫描设备</button>
			<button @tap="stopScan" type="default">⏹ 停止扫描</button>
			<button @tap="closeBluetooth" type="warn">❌ 关闭蓝牙</button>
		</view>

		<!-- 用户输入 -->
		<view v-if="!connected" class="user-input-section">
			<view class="input-group">
				<text>性别:</text>
				<picker @change="onGenderChange" :value="genderIndex" :range="['男', '女']">
					<view class="picker">{{ genderLabel }}</view>
				</picker>
			</view>
			<view class="input-group">
				<text>年龄:</text>
				<input type="number" v-model="age" placeholder="输入年龄" class="input" />
			</view>
		</view>

		<!-- 设备列表 -->
		<view class="devices-summary">发现 {{ devices.length }} 个设备</view>
		<scroll-view class="device-list" scroll-y>
			<view v-for="(device, index) in devices" :key="index" :data-id="device.deviceId"
				:data-name="device.name || device.localName" @tap="connectToDevice" class="device-item">
				<text class="device-name">{{ device.name || device.localName || '未知设备' }}</text>
				<view class="device-info">
					<text>信号: {{ device.RSSI }}dBm ({{ signalLevel(device.RSSI) }})</text>
					<text>设备ID: {{ device.deviceId }}</text>
				</view>
			</view>
		</scroll-view>

		<!-- 连接状态 -->
		<view v-if="connected" class="result-panel">
			<view class="header">
				<text>已连接: {{ connectedName }}</text>
				<button size="mini" @tap="disconnect" type="warn">断开</button>
			</view>

			<!-- 正在等待 -->
			<view v-if="!measurement" class="placeholder">
				🔔 请站上体重秤，等待测量...
			</view>

			<!-- 测量结果 -->
			<view v-else class="measurement-result">
				<view class="section-title">📊 测量结果</view>
				<view class="data-row"><text class="label">身高:</text><text class="value">{{ measurement.height }}
						cm</text></view>
				<view class="data-row"><text class="label">体重:</text><text class="value">{{ measurement.weight }}
						kg</text></view>
				<view class="data-row"><text class="label">BMI:</text><text class="value">{{ measurement.bmi }}</text>
				</view>
				<view class="data-row"><text class="label">体脂率:</text><text
						class="value">{{ measurement.fatRate }}%</text></view>
				<view class="data-row"><text class="label">肌肉率:</text><text
						class="value">{{ measurement.muscleRate }}%</text></view>
				<view class="data-row"><text class="label">水分率:</text><text
						class="value">{{ measurement.waterRate }}%</text></view>
				<view class="data-row"><text class="label">骨量:</text><text class="value">{{ measurement.boneMass }}
						kg</text></view>
				<view class="data-row"><text class="label">基础代谢(BMR):</text><text class="value">{{ measurement.bmr }}
						kcal</text></view>
				<view class="data-row"><text class="label">内脏脂肪:</text><text
						class="value">{{ measurement.visceralFat }}</text></view>
				<view class="data-row"><text class="label">阻抗:</text><text class="value">{{ measurement.impedance }}
						Ω</text></view>
				<view class="data-row"><text class="label">测量时间:</text><text
						class="value">{{ measurement.timeDisplay }}</text></view>
			</view>
		</view>
	</view>
</template>

<script>
	/**
	 * H01EN-PC 蓝牙体重秤协议解析工具 - 优化版
	 * 支持 UUID 精确匹配、自动发送配置、断连监听
	 */

	// 工具函数：格式化时间 YYYY-MM-DD HH:mm:ss
	function formatDateTime(date) {
		const pad = n => String(n).padStart(2, '0');
		return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())} ${pad(date.getHours())}:${pad(date.getMinutes())}:${pad(date.getSeconds())}`;
	}

	// 解析秤返回的19字节数据
	function parseScaleData(buffer) {
		const data = new Uint8Array(buffer);
		console.log("解析前：",data);
		if (data.length < 19) {
			console.warn('数据长度不足', data.length);
			return null;
		}
		if (data[0] !== 0x5A) {
			console.warn('包头错误', data[0].toString(16));
			return null;
		}

		// 校验码：B1 ~ B18 异或
		let checksum = 0;
		for (let i = 0; i < 18; i++) {
			checksum ^= data[i];
		}
		if (checksum !== data[18]) {
			console.warn('校验失败', {
				expected: checksum,
				received: data[18]
			});
			return null;
		}

		const rawHeight = (data[15] << 8) | data[16]; // 单位：0.1cm
		console.log("rawHeight:", rawHeight);
		const rawWeight = (data[2] << 8) | data[3]; // 单位：0.01kg
		console.log("rawWeight:", rawWeight);
		const heightInMeters = rawHeight / 1000; // 转 m
		console.log("heightInMeters:", heightInMeters);
		const weightInKg = rawWeight / 100;
		console.log("weightInKg:", weightInKg);

		return {
			height: rawHeight / 10, // 以 cm 显示
			weight: weightInKg,
			bmi: Number((weightInKg / (heightInMeters * heightInMeters)).toFixed(1)),
			fatRate: ((data[4] << 8) | data[5]) / 10,
			muscleRate: ((data[8] << 8) | data[9]) / 10,
			waterRate: ((data[6] << 8) | data[7]) / 10,
			boneMass: ((data[10] << 8) | data[11]) / 100,
			bmr: (data[12] << 8) | data[13],
			visceralFat: data[1] / 10,
			impedance: (data[14] << 8) | data[17],
			timestamp: new Date(),
			timeDisplay: formatDateTime(new Date()),
			rawData: Array.from(data)
		};
	}

	// 生成发送给秤的用户配置数据
	function createConfigPacket(gender, age) {
		// 1. 性别
		const genderByte = gender === 'female' ? 0x31 : 0x30;

		// 2. 年龄必须是 2 位字符串，不足补前导零
		const ageStr = String(age).padStart(2, '0'); // 如 8 → "08", 12 → "12"

		// 3. 创建 10 字节缓冲区
		const buf = new Uint8Array(10);

		buf[0] = 0x02; // 开始
		buf[1] = 0x53; // 备用
		buf[2] = genderByte; // 性别
		buf[3] = 0x30; // 数据3-1
		buf[4] = 0x30; // 数据3-2
		buf[5] = 0x30; // 数据3-3
		buf[6] = ageStr.charCodeAt(0); // 年龄十位
		buf[7] = ageStr.charCodeAt(1); // 年龄个位

		// 计算校验码：前 8 字节（B1~B8，索引 0~7）
		let checksum = 0;
		for (let i = 0; i <= 7; i++) {
			checksum ^= buf[i];
		}
		buf[8] = checksum; // 校验码
		buf[9] = 0x03; // 结束

		return buf.buffer;
	}

	export default {
		data() {
			return {
				devices: [],
				connected: false,
				connectedName: '',
				deviceId: '',
				serviceId: '',
				writeCharId: '',
				notifyCharId: '',
				measurement: null,
				isScanning: false,

				// 用户信息
				gender: 'female',
				genderIndex: 1,
				genderLabel: '女',
				age: 30,

				// UUID 配置（可外部传入）
				SERVICE_UUID: 'FFE0',
				CHARACTERISTIC_UUID: 'FFE1', // 通常 write 和 notify 是同一个
			};
		},

		methods: {
			signalLevel(rssi) {
				if (rssi >= -60) return '强';
				if (rssi >= -80) return '中';
				if (rssi >= -100) return '弱';
				return '极弱';
			},

			onGenderChange(e) {
				const index = e.target.value;
				this.genderIndex = index;
				this.genderLabel = ['男', '女'][index];
				this.gender = index === 0 ? 'male' : 'female';
			},

			startScan() {
				uni.openBluetoothAdapter({
					success: () => {
						uni.startBluetoothDevicesDiscovery({
							success: () => {
								this.isScanning = true;
								uni.showToast({
									title: '扫描中...',
									icon: 'loading'
								});
								this.listenDevices();
							},
							fail: () => uni.showToast({
								title: '扫描失败',
								icon: 'none'
							})
						});
					},
					fail: () => {
						uni.showModal({
							title: '提示',
							content: '请打开蓝牙',
							showCancel: false
						});
					}
				});
			},

			listenDevices() {
				uni.onBluetoothDeviceFound((res) => {
					res.devices.forEach(device => {
						const exists = this.devices.some(d => d.deviceId === device.deviceId);
						if (!exists) {
							this.devices.push(device);
						}
					});
				});
			},

			stopScan() {
				if (this.isScanning) {
					uni.stopBluetoothDevicesDiscovery();
					this.isScanning = false;
					uni.showToast({
						title: '已停止',
						icon: 'success'
					});
				}
			},

			connectToDevice(e) {
				const deviceId = e.currentTarget.dataset.id;
				const name = e.currentTarget.dataset.name;

				uni.createBLEConnection({
					deviceId,
					success: () => {
						this.connected = true;
						this.connectedName = name;
						this.deviceId = deviceId;
						uni.showToast({
							title: '连接成功',
							icon: 'success'
						});
						this.getServices(deviceId);
					},
					fail: () => uni.showToast({
						title: '连接失败',
						icon: 'none'
					})
				});

				this.stopScan();
			},

			getServices(deviceId) {
				uni.getBLEDeviceServices({
					deviceId,
					success: (res) => {
						// 精确匹配服务 UUID
						const service = res.services.find(s =>
							s.uuid.includes(this.SERVICE_UUID) || s.uuid.includes('ffe0')
						);
						if (!service) {
							uni.showToast({
								title: '未找到服务',
								icon: 'none'
							});
							return;
						}
						this.serviceId = service.uuid;
						this.getCharacteristics(deviceId, service.uuid);
					},
					fail: () => uni.showToast({
						title: '获取服务失败',
						icon: 'none'
					})
				});
			},

			getCharacteristics(deviceId, serviceId) {
				uni.getBLEDeviceCharacteristics({
					deviceId,
					serviceId,
					success: (res) => {
						let foundChar = false;
						res.characteristics.forEach(ch => {
							if (
								(ch.uuid.includes(this.CHARACTERISTIC_UUID) || ch.uuid.includes(
									'ffe1')) &&
								(ch.properties.write || ch.properties.notify)
							) {
								foundChar = true;
								if (ch.properties.write) {
									this.writeCharId = ch.uuid;
								}
								if (ch.properties.notify || ch.properties.indicate) {
									this.notifyCharId = ch.uuid;
									uni.notifyBLECharacteristicValueChange({
										deviceId,
										serviceId,
										characteristicId: ch.uuid,
										state: true
									});
								}
							}
						});

						if (!foundChar) {
							uni.showToast({
								title: '未找到特征值',
								icon: 'none'
							});
							return;
						}

						// 开始监听数据
						this.setupDataListener();

						// 自动发送用户信息
						this.sendUserInfo();
					}
				});
			},

			setupDataListener() {
				uni.onBLECharacteristicValueChange((res) => {
					if (res.characteristicId === this.notifyCharId && res.value) {
						const result = parseScaleData(res.value);
						if (result) {
							this.measurement = result;
							uni.showToast({
								title: '接收成功',
								icon: 'success',
								duration: 1000
							});
						}
					}
				});
			},

			sendUserInfo() {
				if (!this.writeCharId) {
					console.warn('未找到可写特征值，跳过发送');
					return;
				}

				const packet = createConfigPacket(this.gender, parseInt(this.age) || 30);
				
				console.log("发送设备的数据：",packet);

				uni.writeBLECharacteristicValue({
					deviceId: this.deviceId,
					serviceId: this.serviceId,
					characteristicId: this.writeCharId,
					value: packet,
					success: () => console.log('用户信息已发送'),
					fail: (err) => console.warn('发送失败:', err)
				});
			},

			disconnect() {
				uni.closeBLEConnection({
					deviceId: this.deviceId
				});
				this.resetState();
				uni.showToast({
					title: '已断开',
					icon: 'success'
				});
			},

			closeBluetooth() {
				uni.closeBluetoothAdapter();
				this.resetState();
				this.devices = [];
				uni.showToast({
					title: '蓝牙已关闭',
					icon: 'success'
				});
			},

			resetState() {
				this.connected = false;
				this.connectedName = '';
				this.deviceId = '';
				this.serviceId = '';
				this.writeCharId = '';
				this.notifyCharId = '';
				this.measurement = null;
			}
		},

		created() {
			// 监听蓝牙连接状态变化
			uni.onBLEConnectionStateChange((res) => {
				if (!res.connected) {
					this.resetState();
					uni.showToast({
						title: '设备已断开',
						icon: 'none'
					});
				}
			});
		},

		onUnload() {
			this.closeBluetooth();
		}
	};
</script>

<style>
	.container {
		padding: 20rpx;
		font-family: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', 'PingFang SC', sans-serif;
		background-color: #f8f9fa;
	}

	.control-section button {
		margin: 16rpx 0;
		border-radius: 12rpx;
		font-size: 32rpx;
	}

	.user-input-section {
		margin: 20rpx 0;
		padding: 20rpx;
		background: #fff;
		border-radius: 16rpx;
	}

	.input-group {
		display: flex;
		align-items: center;
		margin-bottom: 20rpx;
		font-size: 30rpx;
	}

	.input-group text {
		width: 120rpx;
		color: #333;
	}

	.picker,
	.input {
		width: 400rpx;
		padding: 16rpx;
		border: 1px solid #ddd;
		border-radius: 8rpx;
		font-size: 28rpx;
	}

	.devices-summary {
		margin: 30rpx 0 20rpx;
		font-weight: 600;
		color: #333;
		font-size: 30rpx;
	}

	.device-list {
		height: 500rpx;
		border: 1px solid #ddd;
		border-radius: 16rpx;
		background: #fff;
	}

	.device-item {
		padding: 28rpx;
		border-bottom: 1px solid #eee;
	}

	.device-name {
		font-size: 32rpx;
		font-weight: 600;
		color: #1a1a1a;
	}

	.device-info {
		margin-top: 12rpx;
		font-size: 24rpx;
		color: #666;
		line-height: 1.6;
	}

	.result-panel {
		position: fixed;
		bottom: 0;
		left: 0;
		right: 0;
		background: #eef2ff;
		padding: 30rpx;
		border-top: 2rpx solid #bdc9e2;
		border-radius: 20rpx 20rpx 0 0;
		min-height: 300rpx;
		box-shadow: 0 -4rpx 20rpx rgba(0, 0, 0, 0.1);
	}

	.header {
		display: flex;
		justify-content: space-between;
		align-items: center;
		flex-wrap: wrap;
		gap: 10rpx;
		margin-bottom: 24rpx;
		font-weight: bold;
		color: #0055ff;
	}

	.header button {
		padding: 0 20rpx;
		font-size: 24rpx;
	}

	.measurement-result {
		background: white;
		padding: 30rpx;
		border-radius: 16rpx;
		border: 1px solid #eee;
	}

	.section-title {
		font-size: 34rpx;
		font-weight: bold;
		color: #0055ff;
		margin-bottom: 24rpx;
	}

	.data-row {
		display: flex;
		justify-content: space-between;
		padding: 14rpx 0;
		border-bottom: 1rpx dashed #eee;
		font-size: 28rpx;
		color: #333;
	}

	.label {
		color: #555;
		font-weight: 500;
	}

	.value {
		font-weight: 600;
		color: #000;
	}

	.placeholder {
		text-align: center;
		padding: 40rpx;
		color: #888;
		font-style: italic;
	}
</style>